#include <my_header.h>
#define BLOCK_SIZE (1024* 1024* 8)//设置每次复制的块的大小
/*Usage: ./03_mmapccp2 src dest*/
int main(int argc, char *argv[]){

    //打开源文件
    ARGS_CHECK(argc,3);
    int src_fd = open(argv[1],O_RDONLY);
    ERROR_CHECK(src_fd, -1,"open src");

    //打开目标文件
    int dest_fd = open(argv[2],O_RDWR | O_CREAT | O_TRUNC, 0666);
    ERROR_CHECK(dest_fd, -1, "opend dest");

    //获取源文件的大小
    //使用lseek函数
    //SEEK_END获取末尾的指针，从0位置开始
    //这样就可以获得文件的大小
    //为了后面使用占位，已经循环结束条件做准备
    off_t src_size = lseek(src_fd, 0, SEEK_END);
    ERROR_CHECK(src_size, -1, "lseek error");

    //文件复制之前占位，这样可以判断是否有足够空间复制文件
    int ret = ftruncate(dest_fd,src_size);
    ERROR_CHECK(ret, -1, "ftruncate error");

    //设置每次的初始复制位置（记录此时已经复制了多少字节了）
    //同时这个也是可以作为下一次复制的起点位置
    off_t byte_size = 0;
    while(byte_size < src_size){
        //设置复制的块大小判断
        //因为最后一次复制不可能总是正好是设定好的一个块的大小
        //做一个判断来看看是不是最后一次复制
        //用byte_size + BLOCK_SIZE (目前复制的字节大小 + 设置的复制块大小)
        //如果这两个相加大于src_size说明此时就是最后一次复制
        //这个时候只需要复制src_size - byte_size的字节就可以了
        //这是很常见的if else分支结构可以使用三目运算符
        off_t current_size = (byte_size + BLOCK_SIZE > src_size) ?
            (src_size - byte_size) :
            BLOCK_SIZE;
        //开启源文件的映射
        //源文件只需要读取内容就可以了只需要开启读权限PROR_READ
        void *srcp = mmap(NULL,current_size,PROT_READ,MAP_SHARED,
                          src_fd,byte_size);
        ERROR_CHECK(srcp, MAP_FAILED,"mmap src");

        //开启目标文件映射
        void *destp = mmap(NULL,current_size,PROT_READ | PROT_WRITE,MAP_SHARED,
                           dest_fd,byte_size);
        ERROR_CHECK(destp, MAP_FAILED,"mmap dest");

        // copy file
        // use memcpy 
        // memcpy(dest,src,current_size);
        memcpy(destp, srcp, current_size);

        //free mmap
        munmap(destp,current_size);
        munmap(srcp,current_size);
        // change byte_size num
        byte_size += current_size;
    }
    // close src & dest
    close(src_fd);
    close(dest_fd);
    return 0;
}


